Skip to content

Conversation

Alex-Welsh
Copy link
Member

Added tools/wazuh-scan-images.sh to scan all the container images on a host. The script will be used in the future to scan images on a schedule using Wazuh.

The script first checks if an SBOM exists for the image, if not it'll generate one and scan that rather than the image directly. That makes it much quicker to re-scan images

See also https://wazuh.com/blog/container-image-security-with-wazuh-and-trivy/

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new script, wazuh-scan-images.sh, to scan container images for vulnerabilities. The script is a good addition, but I've identified several areas for improvement in terms of robustness, correctness of the output format, and efficiency. My review includes two high-severity comments addressing a bug in template generation and issues with the CSV output format that would prevent the script from working as intended or produce invalid data. I've also included a medium-severity suggestion to improve the script's flexibility. Please review the detailed comments for specific suggestions.

Comment on lines +9 to +17
# Ensure the custom output template exists
cat <<EOL > "$SBOM_DIR/trivy-custom.tmpl"
"Package","Version Installed","Vulnerability ID","Severity","Title"
{{- range \$ri, \$r := . }}
{{- range \$vi, \$v := .Vulnerabilities }}
"{{ $v.PkgName }}","{{$v.InstalledVersion }}","{{ $v.VulnerabilityID }}","{{$v.Severity }}","{{$v.Title }}"
{{- end}}
{{- end }}
EOL

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current template generation has several issues:

  1. Bug: The $ in template variables like $v.PkgName are not escaped. The shell will substitute them with empty strings, breaking the template and causing trivy to fail.
  2. Incorrect Output: The template includes a static header row, which will be repeated in the output for every image.
  3. Inefficiency: The template is regenerated on every script run.

I suggest replacing this block to create a header-less template only if it doesn't exist. Using <<'EOL' is a safer way to define the template content without needing to escape $ characters. You should then add a command like echo '"Image","Package","Version Installed","Vulnerability ID","Severity","Title"' before the main loop to print the CSV header once.

Suggested change
# Ensure the custom output template exists
cat <<EOL > "$SBOM_DIR/trivy-custom.tmpl"
"Package","Version Installed","Vulnerability ID","Severity","Title"
{{- range \$ri, \$r := . }}
{{- range \$vi, \$v := .Vulnerabilities }}
"{{ $v.PkgName }}","{{$v.InstalledVersion }}","{{ $v.VulnerabilityID }}","{{$v.Severity }}","{{$v.Title }}"
{{- end}}
{{- end }}
EOL
# Ensure the custom output template exists
if [[ ! -f "$SBOM_DIR/trivy-custom.tmpl" ]]; then
cat <<'EOL' > "$SBOM_DIR/trivy-custom.tmpl"
{{- range $ri, $r := . -}}
{{- range $vi, $v := .Vulnerabilities -}}
"{{ $v.PkgName }}","{{$v.InstalledVersion }}","{{ $v.VulnerabilityID }}","{{$v.Severity }}","{{$v.Title }}"
{{- end -}}
{{- end -}}
EOL
fi

Comment on lines 19 to 44
# Loop through each container image and process its SBOM
docker image ls --format "{{.Repository}}:{{.Tag}}" | sort | uniq | while read -r image; do
# Generate SBOM filename
sbom_file="$SBOM_DIR/$(echo "$image" | tr '/:' '_').sbom"

# Generate SBOM if missing
if [[ ! -f "$sbom_file" ]]; then
echo "Generating SBOM for $image..."
if ! trivy image --quiet --format spdx-json --output "$sbom_file" "$image"; then
echo "Failed to generate SBOM for $image. Skipping."
continue
fi
fi

# Scan SBOM and prepend image info to each output line
trivy sbom \
--scanners vuln \
--severity CRITICAL,HIGH \
--ignore-unfixed \
--quiet \
--format template \
--template "@$SBOM_DIR/trivy-custom.tmpl" \
"$sbom_file" | \
awk -v img="$image" '{print "Trivy:\"" img "\"," $0}'
done

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The main processing loop can be improved for robustness and to produce valid CSV output:

  1. Incorrect Output: The awk command produces a non-standard CSV field Trivy:"<image>". The image name should be a proper, quoted CSV field.
  2. Mixed Output: Diagnostic messages are sent to stdout, mixing them with the CSV data. They should be sent to stderr.
  3. Robustness: The script doesn't filter out images with <none> tags and uses a fragile method for generating SBOM filenames.

Here is a suggested replacement for the loop that addresses these points. This assumes you also add a line to print the CSV header (e.g., echo '"Image","Package"...') before this loop, as suggested in another comment.

# Loop through each container image and process its SBOM
docker image ls --format "{{.Repository}}:{{.Tag}}" | grep -v "<none>" | sort -u | while read -r image; do
    # Generate SBOM filename from a hash of the image name for robustness
    sbom_file="$SBOM_DIR/$(echo -n "$image" | sha256sum | cut -d' ' -f1).sbom"

    # Generate SBOM if missing
    if [[ ! -f "$sbom_file" ]]; then
        echo "Generating SBOM for $image..." >&2
        if ! trivy image --quiet --format spdx-json --output "$sbom_file" "$image"; then
            echo "Failed to generate SBOM for $image. Skipping." >&2
            continue
        fi
    fi

    # Scan SBOM and prepend image info to each output line
    trivy sbom \
      --scanners vuln \
      --severity CRITICAL,HIGH \
      --ignore-unfixed \
      --quiet \
      --format template \
      --template "@$SBOM_DIR/trivy-custom.tmpl" \
      "$sbom_file" | \
    awk -v img="$image" 'NF > 0 {print "\"" img "\"," $0}'
done

#!/bin/bash

# SBOM directory path
SBOM_DIR="/opt/kayobe/stackhpc/sboms"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The SBOM directory path is hardcoded. This reduces the script's flexibility. It's better to allow this to be configured via an environment variable, with the current path as a default.

Suggested change
SBOM_DIR="/opt/kayobe/stackhpc/sboms"
SBOM_DIR="${SBOM_DIR:-/opt/kayobe/stackhpc/sboms}"

Added tools/wazuh-scan-images.sh to scan all the container images
running on a host. The script will be used in the future to scan images
on a schedule using Wazuh.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant